# Rspress Vue & Angular 集成示例

这是一个展示如何在Rspress中集成rsbuild-plugin-unplugin-vue和@ng-rspack/build的示例项目，支持同时使用Vue和Angular组件。

## 什么是rsbuild-plugin-unplugin-vue?

rsbuild-plugin-unplugin-vue是一个RSBuild插件，它集成了unplugin-vue来处理Vue单文件组件(SFC)。这个插件可以作为@rsbuild/plugin-vue的替代方案，与RSBuild和RSLib项目无缝协作。

## 快速开始 - Vue集成

### 1. 安装依赖

```bash
npm install rspress vue rsbuild-plugin-unplugin-vue -D
```

### 2. 配置Rspress

在`rspress.config.ts`中添加以下配置：

```typescript
import { defineConfig } from 'rspress/config';
import { pluginUnpluginVue } from 'rsbuild-plugin-unplugin-vue';

export default defineConfig({
  root: 'docs',
  builderPlugins: [
    pluginUnpluginVue({
      unpluginVueOptions: {
        include: ['**/*.vue'],
      },
    }),
  ],
  markdown: {
    mdxRs: false,
  },
});
```

### 3. 创建Vue组件

创建一个简单的Vue组件，例如`components/HelloVue.vue`：

```vue
<template>
  <div class="hello-vue">
    <h2>{{ message }}</h2>
    <p>这是一个在Rspress中使用的Vue组件</p>
    <button @click="count++">点击计数: {{ count }}</button>
  </div>
</template>

<script setup>
import { ref } from 'vue';

const message = 'Hello Vue!';
const count = ref(0);
</script>

<style scoped>
.hello-vue {
  padding: 20px;
  background-color: #f0f8ff;
  border-radius: 8px;
  border: 1px solid #2196f3;
}

h2 {
  color: #2196f3;
  margin-bottom: 10px;
}

button {
  padding: 5px 10px;
  background-color: #2196f3;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}

button:hover {
  background-color: #1976d2;
}
</style>
```

### 4. 创建Vue包装器

由于Rspress默认使用React，我们需要创建一个React包装器来在MDX中使用Vue组件：

```tsx
// components/VueWrapper.tsx
import React, { useEffect, useRef } from 'react';
import { createApp } from 'vue';
import HelloVue from './HelloVue.vue';

const VueWrapper: React.FC = () => {
  const containerRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    if (containerRef.current) {
      const app = createApp(HelloVue);
      app.mount(containerRef.current);

      return () => {
        app.unmount();
      };
    }
  }, []);

  return <div ref={containerRef} />;
};

export default VueWrapper;
```

## 实际演示 - Vue组件

import VueWrapper from './components/VueWrapper.tsx';

<VueWrapper />

## 新增功能：Angular集成

### 1. 安装Angular依赖

```bash
npm install @angular/core @angular/common @angular/compiler @angular/platform-browser @angular/platform-browser-dynamic @ng-rspack/build rxjs zone.js @rsbuild/plugin-typescript -D
```

### 2. 配置TypeScript

创建或更新`tsconfig.json`文件，添加Angular所需的编译器选项：

```json
{
  "compilerOptions": {
    "target": "ES2022",
    "useDefineForClassFields": true,
    "module": "ESNext",
    "lib": ["ES2022", "DOM", "DOM.Iterable"],
    "skipLibCheck": true,
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx",
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true,
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true
  },
  "include": ["docs/**/*"],
  "exclude": ["node_modules"],
  "references": [{ "path": "./tsconfig.node.json" }]
}
```

### 3. 创建Angular组件

创建一个简单的Angular组件：

```typescript
// components/HelloAngular.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'hello-angular',
  template: `
    <div class="angular-component">
      <h2>Hello from Angular!</h2>
      <p>This component is built with Angular {{ version }}</p>
      <div class="counter-section">
        <p>Angular Counter: {{ count }}</p>
        <button (click)="increment()">+</button>
        <button (click)="decrement()">-</button>
      </div>
    </div>
  `,
  styles: [`
    .angular-component {
      padding: 20px;
      background-color: #f0f7ff;
      border-radius: 8px;
      border: 1px solid #3f51b5;
    }
    h2 {
      color: #3f51b5;
      margin-bottom: 10px;
    }
    .counter-section {
      margin-top: 20px;
    }
    button {
      padding: 5px 10px;
      margin: 0 5px;
      background-color: #3f51b5;
      color: white;
      border: none;
      border-radius: 4px;
      cursor: pointer;
    }
    button:hover {
      background-color: #303f9f;
    }
  `]
})
export class HelloAngularComponent {
  version = '16.0.0';
  count = 0;

  increment() {
    this.count++;
  }

  decrement() {
    this.count--;
  }
}
```

### 4. 创建Angular模块

```typescript
// components/app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HelloAngularComponent } from './HelloAngular.component';

@NgModule({
  declarations: [
    HelloAngularComponent
  ],
  imports: [
    BrowserModule
  ],
  providers: [],
  bootstrap: [HelloAngularComponent]
})
export class AppModule { }
```

### 5. 创建Angular包装器

创建React包装器以在MDX中使用Angular组件：

```tsx
// components/AngularWrapper.tsx
import React, { useEffect, useRef } from 'react';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';

const AngularWrapper: React.FC = () => {
  const containerRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    if (containerRef.current) {
      // Create a container for Angular component
      const angularContainer = document.createElement('div');
      angularContainer.id = 'angular-app';
      
      // Add a custom element to host the Angular component
      const componentElement = document.createElement('hello-angular');
      angularContainer.appendChild(componentElement);
      
      // Clear any existing content and append the new container
      containerRef.current.innerHTML = '';
      containerRef.current.appendChild(angularContainer);

      // Bootstrap the Angular application
      platformBrowserDynamic().bootstrapModule(AppModule)
        .catch(err => console.error('Angular bootstrap error:', err));
    }

    // Cleanup function
    return () => {
      if (containerRef.current) {
        containerRef.current.innerHTML = '';
      }
    };
  }, []);

  return (
    <div 
      ref={containerRef} 
      className="angular-wrapper"
      style={{
        width: '100%',
        minHeight: '200px',
        padding: '10px',
      }}
    >
      <div style={{ textAlign: 'center', color: '#666' }}>Loading Angular component...</div>
    </div>
  );
};

export default AngularWrapper;
```

## 实际演示 - Angular组件

import AngularWrapper from './components/AngularWrapper.tsx';

<AngularWrapper />

## 总结

通过rsbuild-plugin-unplugin-vue和@ng-rspack/build，我们可以在Rspress项目中同时使用Vue和Angular组件，这为构建包含多种框架组件示例的文档提供了便利。

虽然目前还有一些限制（如HMR支持），但对于大多数文档场景来说已经足够使用。随着RSBuild、Rspress和@ng-rspack/build的不断发展，相信这些限制在未来的版本中会得到解决，为开发者提供更好的多框架文档体验。
